#include <string.h>
#include <pspkernel.h>
#include <psputility.h>
#include <pspaudio.h>
#include <pspaudiocodec.h>
#include "audio.h"
#include "io_util.h"
#include "rmff.h"
#include "rmff_queue.h"
#include "memory.h"
#include "shin_log.h"

#ifdef audio_enable
unsigned long aac_codec_buffer[65] __attribute__((aligned(64)));

rmff_queue_t audio_queue;

int AudioPlaybackThread(SceSize args, void *argp)
{
	rmff_packet_t *packet;
	debug_log("audio playback thread started");
	while(1)
	{
		packet = rmff_queue_get_packet(&audio_queue);
		sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, packet->data);
	}
	return 0;
}
#endif

SceUID audio_init(rmff_stream_t *stream)
{
#ifdef audio_enable
	SceUID tid;

	if(sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC) < 0 || \
	   sceUtilityLoadModule(PSP_MODULE_AV_AAC) < 0)
	{
		debug_log("load audio module error");
		return 0;
	}
	memset(aac_codec_buffer, 0, sizeof(aac_codec_buffer));
	if(sceAudiocodecCheckNeedMem(aac_codec_buffer, 0x1003) < 0)
		error_log("sceAudiocodecCheckNeedMem failed");
	if(sceAudiocodecGetEDRAM(aac_codec_buffer, 0x1003) < 0)
		error_log("sceAudiocodecGetEDRAM failed");
	aac_codec_buffer[10] = stream->sample_rate;
	if(sceAudiocodecInit(aac_codec_buffer, 0x1003) < 0)
		error_log("sceAudiocodecInit failed");
	if(sceAudioSRCChReserve(SamplePerFrame, stream->sample_rate, \
	                        stream->channels) < 0)
		error_log("Reserve error");
	rmff_queue_init(&audio_queue, audio_queue_size);
	stream->queue = &audio_queue;
	tid = sceKernelCreateThread("audio playback thread", AudioPlaybackThread, \
	                            audio_playback_priority, audio_playback_stack_size, \
								0, 0);
	sceKernelStartThread(tid, 0, 0);
	return tid;
#else
	return 0;
#endif
}

void aac_put_packet(rmff_queue_t *queue, rmff_packet_t *packet)
{
#ifdef audio_enable
	rmff_packet_t *pkt;
	uint32_t sum = 0;
	uint16_t *len, *count, *mix, *buf;
	uint8_t *p;
	int i, ret;

	if(packet->length < 2)goto aac_over;
	count = packet->data;
	sum += 2;
	make_16_be(count);
	*count = *count >> 4 & 0xf;
	sum += *count << 1;
	if(packet->length < sum)goto aac_over;
	len = count + 1;
	for(i = 0; i < *count; i++)
	{
		make_16_be(&len[i]);
		sum += len[i];
	}
	if(packet->length < sum)goto aac_over;
	p = (void*)(len + *count);
	for(i = 0; i < *count; i++)
	{
		pkt = shin_alloc_packet();
		pkt->stream = packet->stream;
		if(!i)pkt->timestamp = packet->timestamp;
		buf = shin_malloc_64(len[i]);
		memcpy(buf, p, len[i]);
		mix = shin_mix_alloc();
		memset(mix, 0, BufferSize);
		aac_codec_buffer[6] = (unsigned long)buf;
		aac_codec_buffer[7] = len[i];
		aac_codec_buffer[8] = (unsigned long)mix;
		aac_codec_buffer[9] = BufferSize;
		ret = sceAudiocodecDecode(aac_codec_buffer, 0x1003);
		shin_free(buf);
		pkt->data = mix;
		pkt->length = BufferSize;
		p += len[i];
		rmff_queue_tail_add(queue, pkt);
		sceKernelDelayThread(1);
	}
aac_over:
#endif
	rmff_release_packet(packet);
}
